package com.doudou.zuul.filter;

import com.doudou.zuul.config.AppConfig;
import com.doudou.zuul.entity.ZuulResponseConstant;
import com.doudou.zuul.utils.TokenUtils;
import com.doudou.zuul.utils.ZuulFilterRequestUtils;
import com.doudou.zuul.utils.ZuulFilterResponseUtils;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.zssj.redis.utils.RedisStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Map;


/**
 * 退出登录的请求
 */
@Component
public class LogoutFilter extends ZuulFilter {

    private static final Logger LOGGER = LoggerFactory.getLogger(LogoutFilter.class);

    @Autowired
    private AppConfig appConfig;

    @Autowired
    private RedisStringUtils redisStringUtils;

    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return 1;
    }

    @Override
    public boolean shouldFilter() {
        String requestUri = ZuulFilterRequestUtils.getRequestUri(RequestContext.getCurrentContext());
        if (requestUri.equals(appConfig.getLogoutUrl())) {
            return true;
        }
        return false;
    }

    @Override
    public Object run() throws ZuulException {

        //处理退出登录逻辑
        RequestContext ctx = RequestContext.getCurrentContext();
        String authorization = ZuulFilterRequestUtils.getRequestHeader(ctx, "Authorization");

        String message = null;
        if (StringUtils.isEmpty(authorization)) {
            logOutWithOutToken(ctx, message, appConfig.isEnableLocalLogPrefix());
            return null;
        }

        String accessToken = null;
        try {
            accessToken = TokenUtils.extractAccessToken(ctx.getRequest());
            if (StringUtils.isEmpty(accessToken)) {
                //按理说要校验合理性
                logOutWithOutToken(ctx, message, appConfig.isEnableLocalLogPrefix());
                return null;
            }

            //加入黑名单
            Map<String, String> map = TokenUtils.extractPlayLoad(accessToken);
            String refreshTokenKey = TokenUtils.extractRefreshTokenKey(map);
            String blackListTokenKey = TokenUtils.extractBlackListTokenKey(map);
            String blackListRefreshTokenKey = TokenUtils.extractBlackListRefreshTokenKey(map);
            redisStringUtils.set(blackListTokenKey, accessToken, TokenUtils.BLACK_LIST_TIME);
            String refreshToken = redisStringUtils.get(refreshTokenKey);
            if (!StringUtils.isEmpty(refreshToken)) {
                redisStringUtils.del(refreshTokenKey);
                redisStringUtils.set(blackListRefreshTokenKey, refreshToken, TokenUtils.BLACK_LIST_TIME);
            }
            ZuulFilterResponseUtils.sendSuccessLogoutToLogin(
                    ctx,
                    ZuulResponseConstant.LOG_OUT_SUCCESS,
                    null);
            return null;
        } catch (Exception e) {

            LOGGER.info("用户退出登录出现异常：{}", e.getMessage(), e);

            message = ZuulFilterResponseUtils.viewTipsMessage(
                    appConfig.isEnableLocalLogPrefix(),
                    appConfig.getLocalAppName(),
                    e.getMessage()
            );
            ZuulFilterResponseUtils.sendBadLogoutToLogin(ctx, message, null);
            return null;
        }
    }


    /**
     * 不携带token退出登录
     *
     * @param ctx
     * @param message
     * @param enableLocalLogPrefix
     */
    private void logOutWithOutToken(RequestContext ctx, String message, boolean enableLocalLogPrefix) {
        message = ZuulFilterResponseUtils.viewTipsMessage(
                appConfig.isEnableLocalLogPrefix(),
                appConfig.getLocalAppName(),
                ZuulResponseConstant.LOG_OUT_WITHOUT_TOKEN
        );
        LOGGER.info(message);
        ZuulFilterResponseUtils.sendBadLogoutToLogin(ctx, message, message);
    }
}
